﻿//-----------------------------------------------------------------------
// <copyright file="FrmMain.cs" company="iTunesEncodeNet">
//  (c) 2009 Vlasenko Dmitry
// </copyright>
//-----------------------------------------------------------------------

namespace ITunesEncodeNet
{
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Windows.Forms;

    /// <summary>
    /// Main form.
    /// </summary>
    public partial class FrmMain : Form
    {
        /// <summary>
        /// Supported file formats.
        /// </summary>
        private string[] formats = { "*.flac", "*.ape" };

        /// <summary>
        /// Founded files.
        /// </summary>
        private List<FileInfo> files = new List<FileInfo>();

        /// <summary>
        /// Tracks to convert.
        /// </summary>
        private List<Track> tracks = new List<Track>();

        /// <summary>
        /// Full path to source directory.
        /// </summary>
        private string sourceDirName;

        /// <summary>
        /// Full path to destination directory.
        /// </summary>
        private string destinationDirName;

        /// <summary>
        /// Initializes a new instance of the FrmMain class.
        /// </summary>
        public FrmMain()
        {
            this.InitializeComponent();
        }

        /// <summary>
        /// Delegate to invoke Convert() asynchronously.
        /// </summary>
        private delegate void Converter();

        /// <summary>
        /// Delegate to invoke SetStatus(string) in FrmMain thread context.
        /// </summary>
        /// <param name="status">Status to set.</param>
        private delegate void SetStatusCallback(string status);

        /// <summary>
        /// Sets status in status bar.
        /// </summary>
        /// <param name="status">Status to set.</param>
        private void SetStatus(string status)
        {
            if (status == null)
            {
                this.lblStatus.Text = string.Empty;
                return;
            }

            this.lblStatus.Text = status;
        }

        /// <summary>
        /// Converts initial *.flac. or *.ape files into result *.m4a files.
        /// </summary>
        private void Convert()
        {
            uint currIndex = 1;

            foreach (Track track in this.tracks)
            {
                string status = string.Format("({0}/{1}) [{2}]", currIndex, this.tracks.Count, track.FileName);
                object[] param = { status };

                this.Invoke(new SetStatusCallback(this.SetStatus), param);

                bool success = false;
                success = track.Decode(this.destinationDirName);
                success = track.Encode();
                track.Move(this.destinationDirName);

                ++currIndex;
            }

            object[] temp = { null };
            this.Invoke(new SetStatusCallback(this.SetStatus), temp);
        }

        /// <summary>
        /// btnSourceDirSelect button Click event handler.
        /// </summary>
        /// <param name="sender">Sender object.</param>
        /// <param name="e">Event arguments.</param>
        private void BtnSourceDirSelect_Click(object sender, EventArgs e)
        {
            this.brdMusicDir.SelectedPath = string.Empty;
            this.brdMusicDir.Description = "Please, select source directory...";
            this.brdMusicDir.ShowNewFolderButton = false;
            this.brdMusicDir.ShowDialog();

            if (!string.IsNullOrEmpty(this.brdMusicDir.SelectedPath))
            {
                this.cbIncludeSubdirs.Enabled = true;
                this.btnDestinationDirSelect.Enabled = true;

                this.sourceDirName = this.brdMusicDir.SelectedPath;
                this.tbSourceDir.Text = this.sourceDirName;

                this.files.Clear();
                this.lvFoundedFiles.Clear();

                DirectoryInfo sourceDir = new DirectoryInfo(this.sourceDirName);

                foreach (string format in this.formats)
                {
                    this.files.AddRange(sourceDir.GetFiles(format));
                }

                foreach (FileInfo file in this.files)
                {
                    this.lvFoundedFiles.Items.Add(new ListViewItem(file.Name));
                }

                if (this.files.Count == 0)
                {
                    this.lvFoundedFiles.Items.Add(new ListViewItem("There are no *.flac or *.ape files in selected directory."));
                    this.tbDestinationDir.Text = string.Empty;

                    this.btnDestinationDirSelect.Enabled = false;
                    this.btnConvert.Enabled = false;
                }
            }
        }

        /// <summary>
        /// btnDestinationDirSelect button Click event handler.
        /// </summary>
        /// <param name="sender">Sender object.</param>
        /// <param name="e">Event arguments.</param>
        private void BtnDestinationDirSelect_Click(object sender, EventArgs e)
        {
            this.brdMusicDir.SelectedPath = string.Empty;
            this.brdMusicDir.Description = "Please, select destination directory...";
            this.brdMusicDir.ShowNewFolderButton = true;
            this.brdMusicDir.ShowDialog();

            if (!string.IsNullOrEmpty(this.brdMusicDir.SelectedPath))
            {
                this.btnConvert.Enabled = true;

                this.destinationDirName = this.brdMusicDir.SelectedPath;
                this.tbDestinationDir.Text = this.destinationDirName;
            }
        }

        /// <summary>
        /// btnConvert button Click event handler.
        /// </summary>
        /// <param name="sender">Sender object.</param>
        /// <param name="e">Event arguments.</param>
        private void BtnConvert_Click(object sender, EventArgs e)
        {
            foreach (FileInfo file in this.files)
            {
                this.tracks.Add(new Track(file.FullName));
            }

            Converter converter = new Converter(this.Convert);
            converter.BeginInvoke(null, null);
        }

        /// <summary>
        /// Scans directory for *.flac or *.ape files.
        /// </summary>
        /// <param name="dirName">Full path to directory.</param>
        private void ScanDirectory(string dirName)
        {
            DirectoryInfo dir = new DirectoryInfo(dirName);

            foreach (string format in this.formats)
            {
                this.files.AddRange(dir.GetFiles(format));
            }

            foreach (DirectoryInfo subDir in dir.GetDirectories())
            {
                this.ScanDirectory(subDir.FullName);
            }
        }

        /// <summary>
        /// cbIncludeSubdirs checkbox CheckStateChanged event handler.
        /// </summary>
        /// <param name="sender">Sender object.</param>
        /// <param name="e">Event arguments.</param>
        private void CbIncludeSubdirs_CheckStateChanged(object sender, EventArgs e)
        {
            this.files.Clear();
            this.lvFoundedFiles.Items.Clear();

            CheckBox checkBox = (CheckBox)sender;

            if (checkBox.CheckState == CheckState.Checked)
            {
                this.btnSourceDirSelect.Enabled = false;
                this.ScanDirectory(this.sourceDirName);
            }
            else
            {
                this.btnSourceDirSelect.Enabled = true;
                DirectoryInfo sourceDir = new DirectoryInfo(this.sourceDirName);

                foreach (string format in this.formats)
                {
                    this.files.AddRange(sourceDir.GetFiles(format));
                }
            }

            foreach (FileInfo file in this.files)
            {
                this.lvFoundedFiles.Items.Add(file.Name);
            }

            if (this.files.Count == 0)
            {
                this.lvFoundedFiles.Items.Add(new ListViewItem("There are no *.flac or *.ape files in selected directories."));

                this.destinationDirName = string.Empty;
                this.tbDestinationDir.Text = this.destinationDirName;

                this.btnDestinationDirSelect.Enabled = false;
                this.btnConvert.Enabled = false;
            }
            else
            {
                this.btnDestinationDirSelect.Enabled = true;
            }
        }

        /// <summary>
        /// exitToolStripMenuItem Click event handler.
        /// </summary>
        /// <param name="sender">Sender object.</param>
        /// <param name="e">Event arguments.</param>
        private void ExitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Application.Exit();
        }
    }
}
